类与对象(上)

类与对象(上)
小米里的大麦一、本节目标
- 面向过程和面向对象初步认识
- 类的引入
- 类的定义
- 类的访问限定符及封装
- 类的作用域
- 类的实例化
- 类的对象大小的计算
- 类成员函数的
this
指针
二、面向过程和面向对象初步认识(过程与面向对象编程)
面向过程编程(ProceduralProgramming):
- 关注“过程”或“步骤”。
- 将问题分解为函数,每个函数执行一个特定的任务。
- 主要依赖函数调用,常见于 C 语言。
1 |
|
面向对象编程(Object-OrientedProgramming):
- 关注“对象”,将数据与操作数据的方法结合。
- 通过对象之间的交互解决问题,常见于 C++。
1 |
|
- C 语言是 面向过程 的,关注 的是 过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
- C++是 基于面向对象 的,关注 的是 对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
三、类的引入(Introduction to Classes)
C 语言结构体中只能定义变量,在 C++中,结构体内不仅可以定义变量,也可以定义函数。 例如: 之前在数据结构初阶中,用 C 语言方式实现的栈,结构体中只能定义变量;但在 C++中,struct
和 class
都可以包含 变量 和 函数。
1 |
|
上面结构体的定义,在 C++中更喜欢用 class
来代替。
四、类的定义(Defining a Class)
类的定义:class
是定义类的关键字。类是对象的蓝图,包含成员变量(属性)和成员函数(方法)。
- 类定义语法:
1 | class ClassName |
两种定义方式:
- 在类体中定义成员函数:这样的函数可能被编译器视为
inline
内联函数。 - 类声明与定义分离:通常将类的声明放在
.h
文件中,成员函数的定义放在.cpp
文件中。注意:成员函数名前需要加类名::
示例 1:类体中定义所有内容:
1 |
|
示例 2:类声明与定义分离:
1 | // Date.h |
五、类的访问限定符及封装(Access Specifiers and Encapsulation)
访问限定符 用于控制类的成员是否能够在类外部访问:
public
:类外可以访问。private
:类外部不能直接访问,只能通过类的内部方法操作。protected
:类外部无法访问,但在继承中可以访问。
封装(Encapsulation):隐藏类的实现细节,仅对外提供公共接口,保证数据的安全性。
1 | class Date |
六、类的作用域(Class Scope)
类的成员定义在类的作用域内,在类外部使用成员函数时,必须用域操作 ::
指定该成员属于哪个作用类。
1 | class Person |
七、类的实例化(Instantiation of Classes)
类的 实例化 是指 通过类的定义创建对象,分配实际的内存空间给成员变量。
1 | class Car |
- 类是对对象进行描述的,是一个 模型 一样的东西,限定了类有哪些成员,定义出一个类 并没有分配实际的内存空间 来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个类,来描述具体学生信息。
类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。
谜语:”年纪不大,胡子一把,主人来了,就喊妈妈” 谜底:山羊
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
1 | int main() |
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
八、类对象模型(Class Object Model)
类对象的大小 由成员变量的大小决定,成员函数的代码不会占用对象的存储空间。
- 空类 的大小为 1 字节,确保每个对象都有唯一标识。
1 | class Empty {}; |
结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐。注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。
结构体内存对齐规则(Struct Memory Alignment Rules)
内容对齐 的规则(【C 语言】结构体内存布局解析——字节对齐_字节对齐规则-CSDN 博客):
- 第一个成员从偏移量为 0 的位置开始。
- 其他成员遵循它们大小的整数倍对齐。
- 总大小为最大对齐数的整数倍。
1 |
|
九、this 指针
在 C++中,this
指针是一个特殊的指针,用于指向调用成员函数的当前对象(当前对象)。它只在类的非静态成员函数下面可用,是传递方式的。是对 this
指针隐式的详细讲解,包括特性、与 C 语言的对比,以及常见的易错点。
1. 引出:什么是 this
指针?
当一个对象调用其类的非静态成员函数时,编译器会自动传递该对象的地址给函数。this
指针就是该对象的地址的成员函数。它可以用于在成员函数中调用该函数的对象的地址成员。
1 | class MyClass |
2. 特性:
隐式传递:
this
指针不需要显式声明,它在所有非静态成员函数中隐式可用。常量性:
this
指针是常量指针,无法修改其指向的对象。即this
类型为MyClass* const
。1
2
3
4
5
6
7
8class MyClass
{
public:
void func()
{
// this = nullptr; // 错误!无法修改this指针的指向
}
};指向当前对象:
this
指向调用该成员函数的当前对象。1
2MyClass obj;
obj.func(); // this指针指向obj在常量成员函数中的
this
指针:在常量成员函数中,this
指针是指向常量的指针,其类型为const MyClass* const
,表示不能this
修改对象的数据成员。1
2
3
4
5
6
7
8class MyClass
{
public:
void func() const
{
// this->value = 10; // 错误!无法修改常成员函数中的对象数据
}
};
3. 与 C 的对比:
C 语言本身不支持类和对象的概念,因此也不存在 this
指针。在 C 中,要模拟类似的行为,通常需要显式传递结构体指针来访问结构体的成员。
1 | C++中的this指针对应于在C语言中手动传递对象指针给函数的做法: |
4. 常见易错点:
修改
this
指针:this
是常量指针,不能修改其指向对象,错误的代码如下:1
2
3
4
5
6
7
8class MyClass
{
public:
void func()
{
// this = nullptr; // 错误!无法修改this指针的指向
}
};在静态成员函数中使用
this
:静态成员函数属于类本身,而不是某个特定对象,因此,静态成员函数中没有this
指针。如果尝试在静态成员函数中使用this
,会出现编译错误。1
2
3
4
5
6
7
8class MyClass
{
public:
static void staticFunc()
{
// this->value = 10; // 错误,静态成员函数没有this指针
}
};返回
*this
:在链式调用时,经常会返回当前对象的引用,返回*this
是合法的用法。常见的用法如下:1
2
3
4
5
6
7
8
9class MyClass
{
public:
MyClass& setValue(int value)
{
this->value = value;
return *this; // 返回当前对象的引用,支持链式调用
}
};在构造函数或解析构造函数中使用
this
:在构造函数中使用this
指针是安全的,但需要注意不要在构造函数中将this
指针导出出去(比如在构造函数中调用虚函数)。在构造函数中,this
指向即将被关注的对象,因此要小心避免对已关注的资源操作。
5. 小结:
this
指针用于指向当前对象,并在非静态成员函数中隐式传递。- 它是一个常量指针,不能修改指向的对象。
- 静态成员函数中没有
this
指针。 this
在 C++中简化了对象成员的访问,而在 C 语言中,需要手动传递结构体指针。
掌握 this
指针有助于理解对象成员的访问方式和 C++类的工作原理。
总结
本文介绍了对象编程中的类、对象、封装、作用域、实例化、对象模型、内存定位和 this
指针的详细内容和代码示例。你可以通过编写这些代码加深理解,并尝试修改运行和它们来更好地掌握这些概念。